package uebung04_w;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;



public class HarrisCornerDetector {
	
	/**
	 * Harris, Stephens [1988] -- A Combined Corner and Edge Detector
	 * 
	 * X		= I conv (-1,0,1)	= dI/dx
	 * Y		= I conv (-1,0,1)^T = dI/dy
	 * A		= X^2 conv w
	 * B		= Y^2 conv w
	 * C		= X*Y conv w
	 * w		= exp -(u^2 + v^2)/2*sigma^2
	 * M		= 	| A C |
	 * 				| C B |
	 * Tr(M) 	= alpha + beta = A + B
	 * Det(M)	= alpha * beta = AB-C^2
	 * R		= Det - k * Tr^2
	 * 
	 * 
	 */
	
	int w;
	int h;
	int size;
	int win = 3;
	double sigma = 1.6;
	double k = 0.5;
	double[] lum; 	// das gegausste helligkeitsbild
	double[] X;		// lum-X-ableitung
	double[] Y;		// lum-Y-ableitung
	double[] R;		// Response
	
	
	public HarrisCornerDetector(int[] rgb, int width, int height) {
		w=width; h=height; size=w*h;
		
		// rgb nach gegausstem, normiertem helligkeitsbild
		lum = getNormedLuminance( tools.Gauss.gaussXY( getLuminance(rgb), w, h, sigma, new int[size] ) );
		
		compute();
		
	} // END Constructor
	
	private void compute(){
		// ableitungen nach x und y bilden
		X = dx(lum,w,h);
		Y = dy(lum,w,h);
		
		// ueber alle pixel gehen + fuer jeden ueber das fenster aufsummieren
		R = new double[size];
		for (int row=0;row<h;row++){ for (int col=0;col<w;col++){
			double A = 0, C = 0, B = 0;
			for(int wrow=-win/2;wrow<=win/2;wrow++){ for (int wcol=-win/2; wcol<=win/2; wcol++) {
				int ind = ((col+wcol+w)%w)+((row+wrow+h)%h)*w;
				A += X[ind]*X[ind];
				B += Y[ind]*Y[ind];
				C += X[ind]*Y[ind];
			}}
			R[row*w+col]=(A*B-C*C)-k*(A+B)*(A+B);
		}}
	}
	
	public static double[] getNormedLuminance(int[] lum){
		double[] norm = new double[lum.length];
		for (int i = 0; i < lum.length; i++) {
			norm[i] = lum[i]/255.;
		}
		return norm;
	}
	public static int[] getLuminance(int[] rgb) {
		int[] lum = new int[rgb.length];
		for (int i = 0; i<rgb.length; i++) {
			int temp = rgb[i], r = (temp>>16)&0xFF, g = (temp>>8)&0xFF, b = temp&0xFF;
			lum[i] = (r*77+g*151+b*28)>>8;
		}
		return lum;
	}
	public static double[] dx(double[] lum, int w, int h) {
		double[] dx = new double[w*h]; 
		for (int i = 0; i < lum.length; i++) {
			int row = i/w, col=i%w, ind = row*w + (col+w+1)%w;
			dx[i] = -(lum[i]-lum[ind]);
		}
		return dx;
	}
	public static double[] dy(double[] lum, int w, int h) {
		double[] dy = new double[w*h];
		for (int i = 0; i < lum.length; i++) {
			int row = i/w, col = i%w, ind = col + ((row+1+h)%h)*w;
			dy[i] = lum[i]-lum[ind];
		}
		return dy;
	}
	
	public static void main(String[] args){
		try {
			// bild laden und nach luminance
			BufferedImage bi = ImageIO.read(HarrisCornerDetector.class.getClassLoader().getResourceAsStream("res/spaceinvaders.png"));
			final int w = bi.getWidth(), h = bi.getHeight();
			int[] rgb = bi.getRGB(0, 0, w, h, new int[w*h], 0, w);
			
			final HarrisCornerDetector hcd = new HarrisCornerDetector(rgb, w, h);
			
			try {
			BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
			img.getRGB(0, 0, w, h, tools.Image.prepare(hcd.R,new int[w*h]), 0, w);
			ImageIO.write(img, "PNG", new File("OUT_harris000.png"));
//			ImageIO.write(img_bayer, "PNG", new File("OUT_lena_bayer.png"));
		}
		catch (IOException iox) {
			iox.printStackTrace();
		}

			
		} catch (IOException e) {e.printStackTrace();}
		
	} // END Method main()
	
} // END CLASS HarrisCornerDetector
